package com.webchat.ugc.service;


import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.webchat.common.bean.APIResponseBean;
import com.webchat.common.bean.APIResponseBeanUtil;
import com.webchat.common.enums.RedisKeyEnum;
import com.webchat.common.exception.BusinessException;
import com.webchat.common.service.RedisService;
import com.webchat.common.service.SnowflakeIdGeneratorService;
import com.webchat.common.util.IDGenerateUtil;
import com.webchat.common.util.JsonUtil;
import com.webchat.common.util.SignUtil;
import com.webchat.domain.dto.payment.PaymentOrderCreateDTO;
import com.webchat.domain.dto.payment.PaymentTransRequestDTO;
import com.webchat.rmi.pay.PaymentApiServiceClient;
import com.webchat.ugc.config.PaymentAppConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.concurrent.locks.ReentrantLock;


@Slf4j
@Service
public class PaymentService {

    @Autowired
    private PaymentApiServiceClient paymentApiServiceClient;

    @Autowired
    private PaymentAppConfig paymentAppConfig;

    @Autowired
    private RedisService redisService;

    private ReentrantLock lock = new ReentrantLock();

    /**
     * 获取交易凭证
     *
     * @return
     */
    public String token() {
        String key = this.getTokenCacheKey();
        String cache = redisService.get(key);
        if (StringUtils.isNotBlank(cache)) {
            return cache;
        }
        String token;
        try {
            lock.lock();
            // 双重检查锁
            token = redisService.get(key);
            if (StringUtils.isNotBlank(token)) {
                return token;
            }
            token = refreshAccessTokenCache();
        } catch (Exception e) {
            throw new BusinessException("支付Token请求失败！");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return token;
    }

    /**
     * 刷新token redis缓存
     *
     * @return
     */
    private String refreshAccessTokenCache() {

        String token = this.getTokenByClient();
        String key = this.getTokenCacheKey();
        redisService.set(key, token, RedisKeyEnum.PAYMENT_ACCESS_TOKEN_CACHE.getExpireTime());
        return token;
    }

    /**
     * 获取Token redis缓存
     * @return
     */
    private String getTokenCacheKey() {

        return RedisKeyEnum.PAYMENT_ACCESS_TOKEN_CACHE.getKey();
    }

    /**
     * 获取token
     *
     * @return
     */
    public String getTokenByClient() {
        String logId = generateLogId();
        // 13位时间戳
        Long timestamp = System.currentTimeMillis();
        // 计算签名（5分钟内有效期）
        // SHA256(sk, "appId - accessKey - timestamp")
        String signature = SignUtil.generateSignature(paymentAppConfig.getSecretKey(),
                                                      String.valueOf(paymentAppConfig.getAppId()),
                                                      paymentAppConfig.getAccessKey(),
                                                      String.valueOf(timestamp));


        APIResponseBean<String> responseBean = paymentApiServiceClient.accessToken(paymentAppConfig.getAppId(),
                                                                                   paymentAppConfig.getAccessKey(),
                                                                                   paymentAppConfig.getSecretKey(),
                                                                                   timestamp,
                                                                                   signature,
                                                                                   logId);
        if (APIResponseBeanUtil.isOk(responseBean)) {
            return responseBean.getData();
        }
        log.error("UGC 支付服务异常 =====> 获取Token异常！logId:{}, responseBean:{}",
                logId, JsonUtil.toJsonString(responseBean));
        throw new BusinessException("支付Token请求失败！");
    }

    /**
     * 获取交易id
     *
     * @return
     */
    public String transId() {

        String accessToken = this.token();
        String logId = this.generateLogId();
        APIResponseBean<String> responseBean = paymentApiServiceClient.transId(accessToken, logId);
        if (APIResponseBeanUtil.isOk(responseBean)) {
            return responseBean.getData();
        }
        log.error("UGC 支付服务异常 =====> 获取TransId异常！logId:{}, responseBean:{}",
                logId, JsonUtil.toJsonString(responseBean));
        throw new BusinessException("支付TransId请求失败！");
    }

    /**
     * 申请创建交易订单，获取交易订单id
     *
     * @param transId
     * @param paymentOrderCreateDTO
     * @return
     */
    public String createOrder(String transId, PaymentOrderCreateDTO paymentOrderCreateDTO) {
        String accessToken = this.token();
        String logId = this.generateLogId();
        APIResponseBean<String> responseBean = paymentApiServiceClient.orderId(accessToken, transId, logId, paymentOrderCreateDTO);
        if (APIResponseBeanUtil.isOk(responseBean)) {
            return responseBean.getData();
        }
        log.error("UGC 支付服务异常 =====> 交易订单创建失败, logId:{}, param:{}",
                logId, JsonUtil.toJsonString(paymentOrderCreateDTO));
        throw new BusinessException("交易订单创建失败！");
    }

    /**
     * 请求支付平台，进行实际交易
     *
     * @param paymentTransRequest
     * @return
     */
    public boolean doTrans(PaymentTransRequestDTO paymentTransRequest) {
        String accessToken = this.token();
        String logId = this.generateLogId();
        APIResponseBean<Boolean> responseBean = paymentApiServiceClient.doTrans(paymentTransRequest, accessToken, logId);
        if (APIResponseBeanUtil.isOk(responseBean)) {
            return ObjectUtils.equals(responseBean.getData(), true);
        }
        log.error("UGC 支付服务异常 =====> 交易处理失败, logId:{}, param:{}",
                logId, JsonUtil.toJsonString(paymentTransRequest));
        return false;
    }


    /**
     * 请求支付平台（wenchat-pay）回滚交易订单及交易明细
     *
     * @param transId
     * @return
     */
    public void doRollBack(String transId) {
        boolean rollbackResult = this.rollBack(transId);
        if (!rollbackResult) {
            // 回滚失败，补偿机制，MQ
        }
    }

    /**
     * 回滚交易事务id相关的所有订单及订单明细
     *
     * @param transId
     * @return
     */
    public boolean rollBack(String transId) {

        String accessToken = this.token();
        String logId = this.generateLogId();
        APIResponseBean<Boolean> responseBean = paymentApiServiceClient.rollback(accessToken, transId, logId);
        if (APIResponseBeanUtil.isOk(responseBean)) {
            return ObjectUtils.equals(responseBean, transId());
        }
        log.error("UGC 支付服务异常 =====> 交易回滚失败, logId:{}, transId:{}", logId, transId);
        return false;
    }

    /**
     * 校验账户余额
     *
     * @param account
     * @param amount
     * @return
     */
    public boolean validateAccountBalance(String account, BigDecimal amount) {
        BigDecimal balance = this.getAccountBalance(account);
        return balance.compareTo(amount) != -1;
    }

    public BigDecimal getAccountBalance(String account) {
        /**
         * 1. 获取access-token 交易凭证
         */
        String accessToken = this.token();
        String logId = this.generateLogId();
        /**
         * RPC请求支付平台，获取账户余额
         */
        APIResponseBean<BigDecimal> responseBean = paymentApiServiceClient.balance(account, accessToken, logId);
        if (APIResponseBeanUtil.isOk(responseBean)) {
            return responseBean.getData();
        }
        log.error("UGC 支付服务异常 =====> 获取 {} 账户余额异常, 异常原因：{}, logId:{}",
                account, responseBean.getMsg(), logId);
        throw new BusinessException(responseBean.getMsg());
    }


    private String generateLogId() {

        return IDGenerateUtil.uuid();
    }
}
